#include "generador_de_relaciones.h"
#include <iostream>

bool GeneradorDeRelaciones::elDescriptorEsSiempre(Lista<Alumno*>* alumnos, DescriptorAlumno descriptor, bool valor) {

	IteradorLista<Alumno*> iterador = alumnos->iterador();
	while(iterador.tieneSiguiente()){
		if(iterador.siguiente()->getValorDelDescriptor(descriptor) != valor){
			return false;
		}
	}

	return true;
}

void GeneradorDeRelaciones::limpiarDescriptores(Lista<Alumno*>* alumnos, ConjuntoDeDescriptores &descriptores){

	IteradorConjuntoDeDescriptores iterador = descriptores.iterador();

	while(iterador.tieneSiguiente()){
		if(this->elDescriptorEsSiempre(alumnos, iterador.get(), true) || this->elDescriptorEsSiempre(alumnos, iterador.get(), false)){
			descriptores.quitarDescriptor(iterador.siguiente());
		}else{
			iterador.siguiente();
		}
	}

}

bool GeneradorDeRelaciones::mayoriaConPromedioSobreCuatro(Lista<Alumno*>* alumnos){

	int cantidadVerdadero = 0;
	int cantidadFalso = 0;

	IteradorLista<Alumno*> iterador = alumnos->iterador();
	while(iterador.tieneSiguiente()){
		if(iterador.siguiente()->getPromedioMayorACuatro()){
			cantidadVerdadero++;
		}else{
			cantidadFalso++;
		}
	}

	return cantidadVerdadero > cantidadFalso;
}

Lista<NodoResultado*>* GeneradorDeRelaciones::generarListaDeRelaciones(Lista<Alumno*>* alumnos,
		DescriptorAlumno calificador, ConjuntoDeDescriptores descriptores) {


	std::cerr << "Descriptores(1): ";
	IteradorConjuntoDeDescriptores it1 = descriptores.iterador();
	while(it1.tieneSiguiente()){
		std::cerr << it1.siguiente();
	}
	std::cerr << std::endl;

	Lista<NodoResultado*>* listaNodos = new Lista<NodoResultado*>;

	if(this->elDescriptorEsSiempre(alumnos, calificador, true)){
		NodoResultado * nodo = new NodoResultado;
		nodo->setDesriptor(calificador);
		nodo->setListaAlumnos(alumnos);
		nodo->setValorDescriptor(true);
		nodo->setListaHijos(0);

		listaNodos->agregar(nodo);

		return listaNodos;
	}

	if(this->elDescriptorEsSiempre(alumnos, calificador, false)){
		NodoResultado * nodo = new NodoResultado;
		nodo->setDesriptor(calificador);
		nodo->setListaAlumnos(alumnos);
		nodo->setValorDescriptor(false);
		nodo->setListaHijos(0);

		listaNodos->agregar(nodo);

		return listaNodos;
	}

	/**
	 * Se eliminan los descriptores que no aportan nada al arbol
	 * de relaciones.
	 */
	this->limpiarDescriptores(alumnos, descriptores);

	std::cerr << "Descriptores(2): ";
	IteradorConjuntoDeDescriptores it2 = descriptores.iterador();
	while(it2.tieneSiguiente()){
		std::cerr << it2.siguiente();
	}
	std::cerr << std::endl;

	if(descriptores.tamanio() == 0){
		NodoResultado * nodo = new NodoResultado;
		nodo->setDesriptor(calificador);
		nodo->setListaAlumnos(alumnos);
		nodo->setValorDescriptor(this->mayoriaConPromedioSobreCuatro(alumnos));
		nodo->setListaHijos(0);

		listaNodos->agregar(nodo);

		return listaNodos;
	}

	CalculadorDeGanancia calculador;
	DescriptorAlumno mejorDescriptor = calculador.descriptorConMayorGanancia(alumnos, descriptores);
	descriptores.quitarDescriptor(mejorDescriptor);


	std::cerr << "Descriptores(3): ";
	IteradorConjuntoDeDescriptores it3 = descriptores.iterador();
	while(it3.tieneSiguiente()){
		std::cerr << it3.siguiente();
	}
	std::cerr << std::endl;

	ClasificadorDeAlumnosPorDescriptor clasificador;
	ClasificacionDeAlumnosPorDescriptor *clasificacion = clasificador.clasificarAlumnos(alumnos, mejorDescriptor);
	if(clasificacion->getListaFalso()->estaVacia() == false){
		NodoResultado * nodo = new NodoResultado;
		nodo->setDesriptor(mejorDescriptor);
		nodo->setListaAlumnos(clasificacion->getListaFalso());
		nodo->setValorDescriptor(false);
		nodo->setListaHijos(this->generarListaDeRelaciones(clasificacion->getListaFalso(), calificador, descriptores));

		listaNodos->agregar(nodo);
	}

	if(clasificacion->getListaVerdadero()->estaVacia() == false){
			NodoResultado * nodo = new NodoResultado;
			nodo->setDesriptor(mejorDescriptor);
			nodo->setListaAlumnos(clasificacion->getListaVerdadero());
			nodo->setValorDescriptor(true);
			nodo->setListaHijos(this->generarListaDeRelaciones(clasificacion->getListaVerdadero(), calificador, descriptores));

			listaNodos->agregar(nodo);
	}

	delete clasificacion;

	return listaNodos;
}


Resultado GeneradorDeRelaciones::generarRelaciones(Lista<Alumno*>* alumnos,
		DescriptorAlumno calificador, ConjuntoDeDescriptores descriptores) {

	Resultado elResultado;

	elResultado.setListaNodosResultado(this->generarListaDeRelaciones(alumnos,
			calificador, descriptores));

	return elResultado;
}
